

#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <Windows.h>

const int MAX_DIGITS = 1000; 

char* Add(char*, char*);
char* Multiply(char*, char*);
char* Fak(char*, char*);
char* Reverse(char*);
char* MultBy10(char*);

struct thread_param;

DWORD WINAPI Fak(LPVOID);

struct thread_param{
	char *from;
	char *to;
	char *result;
};



DWORD WINAPI FakThread(LPVOID param)
{
	thread_param *p = (thread_param*)param;
	char *from = p->from;
	char *to = p->to;

	p->result = Fak(from, to);
	printf("%s\n", p->result);
	return 0;
}

int main(int argc, char* argv[])
{
	printf("%s\n", Fak("41", "50"));
	getchar();

	//get number of threads
	int nr_threads = 1;
	printf("Please enter the number of threads you want to use to calculate 10000!\n");
	scanf("%d", &nr_threads); 
	getchar();
	//create thread array
	HANDLE *thread_array = new HANDLE[nr_threads];

	//create parameter array
	thread_param **params = (thread_param**)malloc(sizeof(thread_param*) * nr_threads);

	//create threads
	for(int i = 1; i <= nr_threads; i++)
	{
		int to = i*(1000/nr_threads);
		int from = (i-1)*(1000/nr_threads)+1;

		*(params+i-1) = new thread_param;
		(*(params+i-1))->from = (char*)malloc(sizeof(char) * MAX_DIGITS);
		params[i-1]->to = (char*)malloc(sizeof(char) * MAX_DIGITS);
		params[i-1]->result = (char*)malloc(sizeof(char) * MAX_DIGITS);

		itoa(from, params[i-1]->from, 10);
		itoa(to, params[i-1]->to, 10);

		HANDLE thread = CreateThread(NULL, 0, FakThread, params[i-1], 0, NULL); 
		thread_array[i-1] = thread;
	}
	//wait for all threads
	while(WAIT_OBJECT_0 != WaitForMultipleObjects(nr_threads, thread_array, TRUE, INFINITE));

	char *result = "1";
	for(int i = 0; i < nr_threads; i++)
	{
		result = Multiply(params[i]->result, result);
	}
	printf("result = %s\n", result);
	
	getchar();
	return 0;
	
}

char* Add(char *a, char *b)
{
	int a_length = strlen(a);
	int b_length = strlen(b);
	int min = 0, max = 0;


	//reverse strings
	char *a_rev = Reverse(a);
	char *b_rev = Reverse(b);
	char *result_rev;
	//get longer strings and copy it into result
	if(strlen(a_rev) >= strlen(b_rev))
	{
		min = strlen(b_rev);
		max = strlen(a_rev);
		result_rev = (char*) malloc(sizeof(char)*strlen(a_rev)+sizeof(char));
		strcpy(result_rev, a_rev);
	}else{
		min = strlen(a_rev);
		max = strlen(b_rev);
		result_rev = (char*) malloc(sizeof(char)*strlen(b_rev)+sizeof(char));
		strcpy(result_rev, b_rev);
	}

	int add_rslt = 0;
	int transf = 0;
	int tmp = 0;

	for(int i = 0; i < min; i++)
	{
		char a_c = a_rev[i];
		char b_c = b_rev[i];
		add_rslt = atoi(&a_c) + atoi(&b_c) + transf;
		if(add_rslt >= 10)
		{
			add_rslt -= 10;
			transf = 1;
		}else transf = 0;
		result_rev[i] = (char)add_rslt + 48;
		tmp++;
	}
	if(transf == 1)
	{
		while(transf == 1)
		{
			char result_rev_c = result_rev[tmp];
			add_rslt = atoi(&result_rev_c)+transf;
			if(add_rslt >= 10)
			{
				add_rslt -= 10;
				transf = 1;
			}else transf = 0;
			result_rev[tmp] = (char)add_rslt + 48;
			tmp++;
		}
		result_rev[++max] = '\0';
	}else result_rev[++max] = '\0';
	

	return Reverse(result_rev);
}

char* Multiply(char *a, char *b)
{
	char *result;// = (char*)malloc(MAX_DIGITS*sizeof(char));
	char **tmp = (char**)malloc(sizeof(char)*strlen(b));
	char **tmp2 = (char**)malloc(sizeof(char)*strlen(b));
	char *b_rev = Reverse(b);

	result = "0";

	for(int i = 0; i < strlen(b); i++)
	{
		tmp[i] = (char*)malloc(sizeof(char)*(strlen(a)+i));
		strcpy(tmp[i], a);
		tmp2[i] = (char*)malloc(sizeof(char)*(strlen(a)+i));
		strcpy(tmp2[i], a);
		for(int j = 0; j < i; j++)
		{
			tmp[i] = MultBy10(tmp[i]);
			tmp2[i] = MultBy10(tmp2[i]);
		}
		char b_c = b_rev[i];
		int b_i = atoi(&b_c);
		for(int j = 1; j < b_i; j++)
		{
			tmp[i] = Add(tmp[i], tmp2[i]);
		}
		if(b_i > 0)
			result = Add(tmp[i], result);
	}	
	
	return result;
}

char* MultBy10(char *number)
{
	char *result = (char*)malloc(sizeof(char)*strlen(number)+sizeof(char));
	strcpy(result, number);
	result[strlen(number)] = '0';
	result[strlen(number)+1] = '\0';
	return result;
}



char* Fak(char* from, char *to)
{
	char* result;
	if(strcmp(from, to) == 0)
	{
		result = (char*)malloc(sizeof(char)*strlen(from));
		strcpy(result, from);
		return result;
	}
	else{
		long newtol = atol(to);
		char newto[MAX_DIGITS];
		newtol--;
		ltoa(newtol, newto, 10); 
		return Multiply(to, Fak(from, newto));
	}
}

char* Reverse(char *string)
{
	char *result = (char*)malloc(sizeof(char)*strlen(string));
	int i, j;
	for(j = 0, i = strlen(string)-1; i >= 0; i--, j++)
	{
		result[j] = string[i];
	}
	result[j] ='\0';
	return result;
}



